package com.xhj.mybatis.plugin;

import com.xhj.mybatis.executor.resultset.ResultSetHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Method;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;

/**
 * ResultSetHandlerInterceptor1
 *
 * @author XJks
 * @description 处理 ResultSetHandler 类的拦截器插件类，用于在执行 SQL 语句时记录日志信息。TODO:注意该类编号为1，用于展示拦截器配置顺序导致的不同效果，先配置的拦截器最后执行，后配置的拦截器最先执行。
 */
@Intercepts({
        // 拦截 ResultSetHandler 接口的 handleResultSets 方法
        @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
})
public class ResultSetHandlerInterceptor1 implements Interceptor {
    /**
     * 日志记录器
     */
    private static final Logger log = LoggerFactory.getLogger(ResultSetHandlerInterceptor1.class);

    /**
     * 方法处理器映射表
     */
    private static final Map<Method, InterceptMethodHandler> methodHandlerMap;

    /**
     * 静态代码块，初始化方法处理器映射表
     */
    static {
        methodHandlerMap = new HashMap<>();
        try {
            // 处理 handleResultSets 方法
            Method handleResultSets = ResultSetHandler.class.getDeclaredMethod("handleResultSets", Statement.class);
            methodHandlerMap.put(handleResultSets, ResultSetHandlerInterceptor1::handleHandleResultSetsMethod);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 重写 intercept 方法，添加日志记录功能
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 获取被拦截的方法
        Method method = invocation.getMethod();
        // 从映射表中获取对应的方法处理器
        InterceptMethodHandler handler = methodHandlerMap.get(method);
        // 如果找到了对应的处理器，则调用处理器进行处理
        if (handler != null) {
            return handler.handle(invocation);
        }
        // 如果没有对应的处理器，则直接执行原方法
        return invocation.proceed();
    }

    /**
     * 处理 handleResultSetsMethod 方法的逻辑
     *
     * @param invocation 调用信息
     * @return 方法执行结果
     * @throws Throwable 可能抛出的异常
     */
    private static Object handleHandleResultSetsMethod(Invocation invocation) throws Throwable {
        // 声明返回结果对象
        Object result = null;
        // 记录开始时间
        long start = System.nanoTime();
        try {
            // 执行被拦截的方法
            result = invocation.proceed();
            // 返回结果
            return result;
        } finally {
            // 计算执行时间，单位为毫秒
            long executionTime = (System.nanoTime() - start) / 1_000_000;
            // 获取结果的简要视图信息
            String resultView = InterceptorUtil.getResultView(result);
            // 记录日志信息
            log.info("[ResultSetHandler1] handleResultSets | executionTime={}ms | resultView={}", executionTime, resultView);
        }
    }
}
